import pygame
import random

#游戏窗口区域(矩形区域)
SCREEN_RECT=pygame.Rect(0,0,480,700)
FRAME_INTERVAL=10
HERO_BOMB_COUNT = 3
#英雄飞机默认初始位置
HERO_DEFAULT_MTD_BOTTOM=(SCREEN_RECT.centerx,SCREEN_RECT.bottom -90)
#英雄飞机牺牲事件
HERO_DEAD_EVENT = pygame.USEREVENT
#取消英雄飞机无敌的事件
HERO_POWER_OFF_EVENT = pygame.USEREVENT + 1
#英雄飞机发射子弹事件
HERO_FIRE_EVENT = pygame.USEREVENT + 2
#投放道具事件
THROW_SUPPLY_EVENT = pygame.USEREVENT + 3
#结束子弹增强定时器的事件
BULLET_ENHANCED_OFF_EVENT = pygame.USEREVENT + 4


class GameSprite(pygame.sprite.Sprite):
    #游戏精灵类
    res_path="./res/images/"
    def __init__(self, image_name, speed, *groups):
        "构造方法"
        super().__init__(*groups)
        #图像
        self.image = pygame.image.load(self.res_path + image_name)
        self.rect = self.image.get_rect()
        self.speed =speed
        #图像遮罩,可以提高碰撞检测的执行性能
        self.mask = pygame.mask.from_surface(self.image)
    def update(self, *args):
        self.rect.y += self.speed

class Background(GameSprite):
    #背景精灵类
    def __init__(self, is_alt, *groups):
        super().__init__("background.png",1,*groups)
        if is_alt:
            self.rect.y = -self.rect.h
    def update(self, *args):
        super().update(*args)
        if self.rect.y >= self.rect.h:
            self.rect.y = -self.rect.h

class StatusButton(GameSprite):
    #状态按钮类
    def __init__(self, image_names, *groups):
        super().__init__(image_names[0],0,*groups)
        #加载图像
        self.images = [pygame.image.load(self.res_path + name)
                       for name in image_names]
    def switch_status(self, is_pause):
        #切换状态
        self.image = self.images[1 if is_pause else 0]

class Label(pygame.sprite.Sprite):
    #文本标签精灵
    font_path="./res/font/font.ttf"
    def __init__(self,text,size,color,*groups):
        #构造方法
        super().__init__(*groups)
        self.font=pygame.font.Font(self.font_path,size)
        self.color=color
        self.image=self.font.render(text,True,self.color)
        self.rect=self.image.get_rect()
    def set_text(self, text):
        self.image=self.font.render(text, True, self.color)
        self.rect = self.image.get_rect()

class Plane(GameSprite):
    #飞机类
    def __init__(self, hp,speed,value,wav_name,
                 normal_names,hurt_name,destroy_names, *groups):
        #构造方法
        super().__init__(normal_names[0], speed, *groups)
        #飞机属性
        self.hp=hp
        self.max_hp=hp
        self.value=value
        self.wav_name=wav_name
        #图像属性，正常图像列表及索引
        self.normal_images = [pygame.image.load(self.res_path + name) for name in normal_names]
        self.normal_index = 0
        #受伤的图像
        self.hurt_image = pygame.image.load(self.res_path + hurt_name)
        #被摧毁图像列表及索引
        self.destroy_images = [pygame.image.load(self.res_path + name) for name in destroy_names]
        self.destroy_index = 0

    def reset_plane(self):
        #重置飞机
        self.hp=self.max_hp
        self.normal_index=0
        self.destroy_index=0
        self.image = self.normal_images[0]

    def update(self, *args):
        if not args[0]:
            return
        #判断飞机状态
        if self.hp==self.max_hp:
            self.image = self.normal_images[self.normal_index]
            count = len(self.normal_images)
            self.normal_index = (self.normal_index + 1) % count
        elif self.hp>0:
            self.image = self.hurt_image
        else:
            #判断是否显示到最后一张图像，若是说明飞机完全被摧毁
            if self.destroy_index<len(self.destroy_images):
                self.image = self.destroy_images[self.destroy_index]
                self.destroy_index +=1
            else:
                self.reset_plane()

class Enemy(Plane):
    #敌机类
    def __init__(self,kind,max_speed,*groups):
        self.kind =kind
        self.max_speed=max_speed
        #根据类型调用父类方法传递不同参数
        if kind == 0:
            super().__init__(1,1,1000,"enemy1_down.wav",
                             ["enemy1.png"],"enemy1.png",
                             ["enemy1_down%d.png" % i for i in range(1,5)], *groups)
        elif kind ==1:
            super().__init__(6,1,6000,"enemy2_down.wav",
                             ["enemy2.png"],"enemy2_hit.png",
                             ["enemy2_down%d.png" % i for i in range(1,5)], *groups)
        else:
            super().__init__(15,1,15000,"enemy3_down.wav",
                             ["enemy3_n1.png","enemy3_n2.png"],
                             "enemy3_hit.png",
                             ["enemy3_down%d.png" % i for i in range(1,7)], *groups)
        #调用重置飞机方法，设置敌机初始位置和速度
        self.reset_plane()

    def reset_plane(self):
        #设置初始速度
        self.speed = random.randint(1, self.max_speed)
        #重置敌机
        super().reset_plane()
        #设置随机x值
        x = random.randint(0,SCREEN_RECT.w - self.rect.w)
        #设置随机y值
        y =  self.rect.h - SCREEN_RECT.h
        self.rect.topleft =(x,y)

    def update(self, *args):
        #调用父类方法更新敌机图像
        super().update(*args)
        #判断敌机是否被摧毁，若没有，则根据速度更新敌机位置
        if self.hp>0:
            self.rect.y += self.speed
        #判断是否飞出屏幕,如果是，重置敌机
        if self.rect.y >= SCREEN_RECT.h:
            self.reset_plane()

class Hero(Plane):
    #英雄飞机类
    def __init__(self, *groups):
        super().__init__(1000, 5, 0, "me_down.wav",
                         ["me%d.png" % i for i in range(1,3)], "me1.png",
                         ["me_destroy_%d.png" % i for i in range(1,5)], *groups)
        self.is_power = False
        self.bomb_count = HERO_BOMB_COUNT
        self.bullets_kind = 0
        self.bullets_group = pygame.sprite.Group()
        #初始位置
        self.rect.midbottom = HERO_DEFAULT_MTD_BOTTOM
        #设置0.2s发射子弹定时器事件
        pygame.time.set_timer(HERO_FIRE_EVENT, 200)

    def update(self, *args):
        super().update(*args)
        if len(args) !=3 or self.hp<=0:
            return
        #调整水平移动距离
        self.rect.x += args[1] * self.speed
        self.rect.y += args[2] * self.speed
        #限定在游戏窗口内部移动
        self.rect.x =0 if self.rect.x <0 else self.rect.x
        if self.rect.right > SCREEN_RECT.right:
            self.rect.right = SCREEN_RECT.right
        self.rect.y = 0 if self.rect.y <0 else self.rect.y
        if self.rect.bottom >SCREEN_RECT.bottom:
            self.rect.bottom = SCREEN_RECT.bottom

    def blowup(self, enemies_group):
        if self.bomb_count <= 0 or self.hp <= 0:
            return 0
        self.bomb_count -= 1
        score = 0
        count =0
        for enemy in enemies_group.sprites():
            #判断敌机是否进入游戏窗口
            if enemy.rect.bottom >0:
                score += enemy.value
                count +=1
                enemy.hp=0
        print("炸毁了%d架敌机,得分%d" % (count,score))
        return score

    def reset_plane(self):
        #调用父类方法重置图像相关属性
        super().reset_plane()
        self.is_power =True
        self.bomb_count =HERO_BOMB_COUNT
        self.bullets_kind =0
        #发布英雄牺牲事件
        pygame.event.post(pygame.event.Event(HERO_DEAD_EVENT))
        #设置3s之后取消无敌定时器事件
        pygame.time.set_timer(HERO_POWER_OFF_EVENT,3000)

    def fire(self, display_group):
        #需要将子弹精灵添加到2个精灵组
        groups = (self.bullets_group, display_group)
        #测试子弹增强效果
        #self.bullets_kind = 1
        for i in range(3):
            #创建子弹精灵
            bullet1 = Bullet(self.bullets_kind, *groups)
            #计算子弹的垂直位置
            y = self.rect.y - i*15
            #判断子弹类型
            if self.bullets_kind == 0:
                bullet1.rect.midbottom = (self.rect.centerx, y)
            else:
                bullet1.rect.midbottom = (self.rect.centerx - 20, y)
                #再创建一个子弹
                bullet2 = Bullet(self.bullets_kind, *groups)
                bullet2.rect.midbottom = (self.rect.centerx + 20, y)

class Bullet(GameSprite):
    #子弹类
    def __init__(self,kind,*groups):
        image_name = "bullet1.png" if kind == 0 else "bullet2.png"
        super().__init__(image_name,-12,*groups)
        self.damage = 1

    def update(self, *args):
        super().update(*args)
        #判断是否从上方飞出窗口
        if self.rect.bottom <0:
            self.kill()

class Supply(GameSprite):
    def __init__(self, kind, *groups):
        image_name = "%s_supply.png" % ("bomb" if kind == 0 else "bullet")
        super().__init__(image_name, 5, *groups)
        #道具类型
        self.kind = kind
        self.wav_name = "get_%s.wav" % ("bomb" if kind ==0 else "bullet")
        #初始位置
        self.rect.y = SCREEN_RECT.h

    def throw_supply(self):
        #投放道具
        self.rect.bottom = 0
        self.rect.x = random.randint(0, SCREEN_RECT.w - self.rect.w)

    def update(self, *args):
        #更新位置，在屏幕下方不移动
        if self.rect.h > SCREEN_RECT.h:
            return
        #调用父类的方法,沿垂直方向移动
        super().update(*args)